package com.xinshujia.config.mqtt;

import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory;
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;

/**
 * *************************************
 * *   @author: 野狼上校               **
 * *   @since: 2024-07-25 16:26       **
 * *   @version: 1.0                  **
 * *************************************
 * <p>
 * mqtt服务类
 * 一种基于发布/订阅（publish/subscribe）模式的轻量级通讯协议，通过订阅相应的主题来获取消息，
 * 是物联网（Internet of Thing）中的一个标准传输协议
 * ClientId是MQTT客户端的标识。MQTT服务端用该标识来识别客户端。因此ClientId必须是独立的。
 * clientID需为全局唯一。如果不同的设备使用相同的clientID同时连接物联网平台，那么先连接的那个设备会被强制断开。
 * <p>
 * mqtt客户端配置
 */
@Configuration
public class MqttConfig {
    // mqtt服务器地址
    @Value("${spring.mqtt.url}")
    private String hostUrl;
    // mqtt账号
    @Value("${spring.mqtt.username}")
    private String username;
    // mqtt密码
    @Value("${spring.mqtt.password}")
    private String password;
    // 遗嘱主题
    @Value("${spring.mqtt.topic.will}")
    private String willTopic;


    /**
     * 创建和管理MQTT客户端的连接工厂
     */
    @Bean
    public MqttPahoClientFactory mqttClientFactory() {
        DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
        // 设置连接参数
        MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
        // mqtt 账号
        mqttConnectOptions.setUserName(username);
        // mqtt 密码
        mqttConnectOptions.setPassword(password.toCharArray());
        // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录，
        // 把配置里的 cleanSession 设为false，客户端掉线后 服务器端不会清除session，
        // 当重连后可以接收之前订阅主题的消息。当客户端上线后会接受到它离线的这段时间的消息
        // true 表示每次连接到服务器都以新的身份连接
        // mqttConnectOptions.setCleanSession(false);
        mqttConnectOptions.setCleanSession(true);
        // mqtt 服务器地址
        mqttConnectOptions.setServerURIs(new String[]{hostUrl});
        // 设置连接超时时间 单位为秒
        mqttConnectOptions.setConnectionTimeout(100);
        // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线，但这个方法并没有重连的机制
        mqttConnectOptions.setKeepAliveInterval(20);
        // 控制客户端在收到服务器对之前消息的确认之前，可以同时发送到服务器的最大消息数
        mqttConnectOptions.setMaxInflight(1000);
        // 设置“遗嘱”消息的话题，若客户端与服务器之间的连接意外中断，服务器将发布客户端的“遗嘱”消息。
        mqttConnectOptions.setWill(willTopic, "offline".getBytes(), 2, false);

        factory.setConnectionOptions(mqttConnectOptions);
        return factory;
    }
}
